package org.wheel.plugins.toolkit.sql.capability.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import org.wheel.plugins.toolkit.sql.capability.LambdaSubCollection;
import org.wheel.plugins.toolkit.sql.core.LambdaQueryWrapper;
import org.wheel.plugins.toolkit.sql.core.WrapperContext;
import org.wheel.plugins.toolkit.sql.helper.ColumnRef;
import org.wheel.plugins.toolkit.sql.helper.LambdaUtils;
import org.wheel.plugins.toolkit.sql.helper.SFunction;
import org.wheel.plugins.toolkit.sql.segment.SelectBuilder;

import java.util.Collection;
import java.util.function.Consumer;

public class LambdaSubCollectionImpl<W extends LambdaSubCollection<W, T>, T>
        implements LambdaSubCollection<W, T> {

    private final String parentFieldAlias;
    private final LambdaQueryWrapper<T> wrapper;
    private WrapperContext context;

    public LambdaSubCollectionImpl(String parentFieldAlias, LambdaQueryWrapper<T> wrapper){
        this.parentFieldAlias = parentFieldAlias;
        this.wrapper = wrapper;
        this.context = wrapper.getContext();
    }

    private W self() {
        return (W) this;
    }

    @Override
    public <A> W result(SFunction<A, ?> assocFn, String columnAlias) {
        if(StrUtil.isBlank(columnAlias)) {
            columnAlias = LambdaUtils.getFieldName(assocFn);
        }

        if (StrUtil.isNotBlank(parentFieldAlias)) {
            columnAlias = StrUtil.join(StrUtil.DOT, parentFieldAlias, columnAlias);
        }
        wrapper.selectAs(assocFn, columnAlias);
        return self();
    }

    @Override
    public <A, B> W association(String tableAlias, Class<A> assocClass, SFunction<B, ?> assocFn, Consumer<LambdaSubCollection<W, T>> nestedQuery) {
        String field = LambdaUtils.getFieldName(assocFn);
        if(StrUtil.isNotBlank(parentFieldAlias)){
            field = StrUtil.join(StrUtil.DOT, parentFieldAlias, field);
        }
        ColumnRef[] segs = SelectBuilder.collection(tableAlias, field, assocClass, wrapper);
        wrapper.collection(SelectBuilder.join(segs));

        if(ObjectUtil.isNotNull(nestedQuery)){
            System.out.println("nestedQuery parent field: "+field);
            LambdaSubCollection<W, T> subCollection = new LambdaSubCollectionImpl<>(field, this.wrapper);
            nestedQuery.accept(subCollection);
        }
        return self();
    }

    @Override
    public <A, B, C, D extends LambdaSubCollection<D, E>, E> W collection(String tableAlias, Class<A> collectionClass, SFunction<B, Collection<C>> collectionFn,
                                                                                                               Consumer<LambdaSubCollection<D, E>> nestedQuery) {
        String field = LambdaUtils.getFieldName(collectionFn);
        if(StrUtil.isNotBlank(parentFieldAlias)){
            field = StrUtil.join(StrUtil.DOT, parentFieldAlias, field);
        }

        ColumnRef[] segs = SelectBuilder.collection(tableAlias, field, collectionClass, wrapper);
        wrapper.collection(SelectBuilder.join(segs));


        if(ObjectUtil.isNotNull(nestedQuery)){
            System.out.println("nestedQuery parent field: "+field);
            LambdaSubCollection<D, E> subCollection = new LambdaSubCollectionImpl<D, E>(field, (LambdaQueryWrapper<E>) this.wrapper);
            nestedQuery.accept(subCollection);
        }
        return self();
    }
}
